﻿using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.Xna.Framework.Graphics;

namespace Daybreak.Core.Rendering
{
    public class VertexData
    {
        public static VertexElement[] TengentVertexElements;

        public VertexDeclaration CommonDeclaration;
        public VertexDeclaration TengentDeclaration;

        /// <summary>
        /// The vertex buffer (Pos, Norm, Texcooed & skin info) to render with.
        /// </summary>
        public VertexBuffer CommonVertexBuffer;
        /// <summary>
        /// The tangent buffer 
        /// </summary>
        public VertexBuffer TangentVertexBuffer;

        /// <summary>
        /// The number of vertices to use from the vertex buffer.
        /// </summary>
        public int VertexCount;

        /// <summary>
        /// The vertex to start at in the vertex buffer.
        /// </summary>
        public int BaseVertex;

        /// <summary>
        /// Vertex stride in bytes
        /// </summary>
        public int VertexStride;

        public VertexData()
        {
        }

        static VertexData()
        {
            TengentVertexElements = new VertexElement[2];

            TengentVertexElements[0] = new VertexElement(1, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Tangent, 0);
            TengentVertexElements[1] = new VertexElement(1, 12, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Binormal, 0);
        }

        internal void CreateTangentBuffer()
        {
            if (TangentVertexBuffer != null)
                return;

            if (CommonVertexBuffer == null)
                return;

            TangentVertexBuffer = new VertexBuffer(Engine.GraphicsDevice, 24 * VertexCount, BufferUsage.None);

        }

        internal void ApplyToDevice(GraphicsDevice device, bool useTangents)
        {
            if (!useTangents)
            {
                device.VertexDeclaration = CommonDeclaration;
                device.Vertices[0].SetSource(CommonVertexBuffer, 0, VertexStride);
            }
            else
            {
                device.VertexDeclaration = EnsureTangents(device);
                device.Vertices[0].SetSource(CommonVertexBuffer, 0, VertexStride);
                device.Vertices[1].SetSource(TangentVertexBuffer, 0, 24);
            }

        }

        private VertexDeclaration EnsureTangents(GraphicsDevice device)
        {

            if (TengentDeclaration == null)
            {
                List<VertexElement> decl = new List<VertexElement>(8);

                decl.AddRange(CommonDeclaration.GetVertexElements());
                decl.AddRange(TengentVertexElements);

                VertexElement[] elems = decl.ToArray();

                TengentDeclaration = new VertexDeclaration(device, elems);
            }

            return TengentDeclaration;
        }

        public static VertexData Create(int vertexCount, VertexElement[] vertexElements, BufferUsage usage)
        {
            if (!Engine.IsReady)
                return null;

            VertexData vd = new VertexData();

            vd.VertexCount = vertexCount;

            vd.CommonDeclaration = new VertexDeclaration(Engine.GraphicsDevice, vertexElements);

            int size = vd.CommonDeclaration.GetVertexStrideSize(0);

            vd.CommonVertexBuffer = new VertexBuffer(Engine.GraphicsDevice, size * vertexCount, usage);
            vd.VertexStride = size;

            return vd;

        }

    }
}
